home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / ExportWAVSample.c < prev    next >
Text File  |  1994-08-23  |  13KB  |  401 lines

  1. /* ExportWAVSample.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ExportWAVSample.h"
  31. #include "SampleConsts.h"
  32. #include "SampleStorageActual.h"
  33. #include "Memory.h"
  34. #include "Files.h"
  35. #include "Alert.h"
  36. #include "BufferedFileOutput.h"
  37.  
  38.  
  39. /* prototype for the function that actually does the work. */
  40. static MyBoolean        TryToExportWAVFile(BufferedOutputRec* File,
  41.                                             SampleStorageActualRec* Sample, long SamplingRate);
  42.  
  43.  
  44. /* this routine saves the data in the provided sample storage object as a WAVE */
  45. /* formatted file.  it handles any error reporting to the user.  the object is */
  46. /* NOT disposed, so the caller has to do that. */
  47. void                                ExportWAVSample(struct SampleStorageActualRec* TheSample,
  48.                                             long SamplingRate)
  49.     {
  50.         FileSpec*                    WhereToSave;
  51.  
  52.         CheckPtrExistence(TheSample);
  53.         WhereToSave = PutFile("Untitled.WAV");
  54.         if (WhereToSave != NIL)
  55.             {
  56.                 if (CreateFile(WhereToSave,ApplicationCreator,CODE4BYTES('?','?','?','?')))
  57.                     {
  58.                         FileType*                    TheFileDescriptor;
  59.  
  60.                         if (OpenFile(WhereToSave,&TheFileDescriptor,eReadAndWrite))
  61.                             {
  62.                                 BufferedOutputRec*    BufferedFileThing;
  63.  
  64.                                 BufferedFileThing = NewBufferedOutput(TheFileDescriptor);
  65.                                 if (BufferedFileThing != NIL)
  66.                                     {
  67.                                         (void)TryToExportWAVFile(BufferedFileThing,TheSample,SamplingRate);
  68.                                         EndBufferedOutput(BufferedFileThing);
  69.                                     }
  70.                                  else
  71.                                     {
  72.                                         AlertHalt("There is not enough memory available to export "
  73.                                             "the file.",NIL);
  74.                                     }
  75.                                 CloseFile(TheFileDescriptor);
  76.                             }
  77.                          else
  78.                             {
  79.                                 AlertHalt("Unable to open the file for writing.",NIL);
  80.                             }
  81.                     }
  82.                  else
  83.                     {
  84.                         AlertHalt("The file could not be created.",NIL);
  85.                     }
  86.                 DisposeFileSpec(WhereToSave);
  87.             }
  88.     }
  89.  
  90.  
  91. /* RIFF file format, with WAVE information */
  92. /*  'RIFF' */
  93. /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  94. /*  'WAVE' */
  95. /*  'fmt ' */
  96. /*  4-byte little endian length descriptor for the 'fmt ' header block */
  97. /*      - this should be 16.  if not, then it's some other kind of WAV file */
  98. /*  2-byte little endian format descriptor.  this is always here. */
  99. /*      - 1 = PCM */
  100. /*  2-byte little endian number of channels. */
  101. /*  4-byte little endian sampling rate integer. */
  102. /*  4-byte little endian average bytes per second. */
  103. /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  104. /*    stereo, this is 4. */
  105. /*  2-byte little endian number of bits. */
  106. /*      - 8 = 8-bit */
  107. /*      - 16 = 16-bit */
  108. /*  'data' */
  109. /*  4-byte little endian length of sample data descriptor */
  110. /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  111. /*    from -32768 to 32767. */
  112. static MyBoolean        TryToExportWAVFile(BufferedOutputRec* File,
  113.                                             SampleStorageActualRec* Sample, long SamplingRate)
  114.     {
  115.         unsigned long            TotalSampleLength;
  116.         unsigned long            TotalChunkLength;
  117.         unsigned long            BytesPerSecond;
  118.         unsigned short        BlockAlignment;
  119.  
  120.         CheckPtrExistence(File);
  121.         CheckPtrExistence(Sample);
  122.  
  123.         /*  'RIFF' */
  124.         if (!WriteBufferedOutput(File,4,"RIFF"))
  125.             {
  126.              DiskErrorPoint:
  127.                 AlertHalt("A file error occurred and the sample couldn't be exported.",NIL);
  128.                 return False;
  129.             }
  130.  
  131.         /* figure out how long chunk will be */
  132.         switch (GetSampleStorageActualNumBits(Sample))
  133.             {
  134.                 default:
  135.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  136.                         "GetSampleStorageActualNumBits"));
  137.                     break;
  138.                 case eSample8bit:
  139.                     switch (GetSampleStorageActualNumChannels(Sample))
  140.                         {
  141.                             default:
  142.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  143.                                     "GetSampleStorageActualNumBits"));
  144.                                 break;
  145.                             case eSampleMono:
  146.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 1;
  147.                                 BytesPerSecond = SamplingRate * 1;
  148.                                 BlockAlignment = 1;
  149.                                 break;
  150.                             case eSampleStereo:
  151.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 2;
  152.                                 BytesPerSecond = SamplingRate * 2;
  153.                                 BlockAlignment = 2;
  154.                                 break;
  155.                         }
  156.                     break;
  157.                 case eSample16bit:
  158.                     switch (GetSampleStorageActualNumChannels(Sample))
  159.                         {
  160.                             default:
  161.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  162.                                     "GetSampleStorageActualNumBits"));
  163.                                 break;
  164.                             case eSampleMono:
  165.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 2;
  166.                                 BytesPerSecond = SamplingRate * 2;
  167.                                 BlockAlignment = 2;
  168.                                 break;
  169.                             case eSampleStereo:
  170.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 4;
  171.                                 BytesPerSecond = SamplingRate * 4;
  172.                                 BlockAlignment = 4;
  173.                                 break;
  174.                         }
  175.                     break;
  176.             }
  177.         TotalChunkLength = TotalSampleLength + 36;
  178.  
  179.         /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  180.         if (!WriteBufferedUnsignedLongLittleEndian(File,TotalChunkLength))
  181.             {
  182.                 goto DiskErrorPoint;
  183.             }
  184.  
  185.         /*  'WAVE' */
  186.         /*  'fmt ' */
  187.         if (!WriteBufferedOutput(File,8,"WAVEfmt "))
  188.             {
  189.                 goto DiskErrorPoint;
  190.             }
  191.  
  192.         /*  4-byte little endian length descriptor for the 'fmt ' header block */
  193.         /*      - this should be 16.  if not, then it's some other kind of WAV file */
  194.         if (!WriteBufferedUnsignedLongLittleEndian(File,16))
  195.             {
  196.                 goto DiskErrorPoint;
  197.             }
  198.  
  199.         /*  2-byte little endian format descriptor.  this is always here. */
  200.         /*      - 1 = PCM */
  201.         if (!WriteBufferedUnsignedShortLittleEndian(File,1))
  202.             {
  203.                 goto DiskErrorPoint;
  204.             }
  205.  
  206.         /*  2-byte little endian number of channels. */
  207.         switch (GetSampleStorageActualNumChannels(Sample))
  208.             {
  209.                 default:
  210.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  211.                         "GetSampleStorageActualNumBits"));
  212.                     break;
  213.                 case eSampleMono:
  214.                     if (!WriteBufferedUnsignedShortLittleEndian(File,1))
  215.                         {
  216.                             goto DiskErrorPoint;
  217.                         }
  218.                     break;
  219.                 case eSampleStereo:
  220.                     if (!WriteBufferedUnsignedShortLittleEndian(File,2))
  221.                         {
  222.                             goto DiskErrorPoint;
  223.                         }
  224.                     break;
  225.             }
  226.  
  227.         /*  4-byte little endian sampling rate integer. */
  228.         if (!WriteBufferedUnsignedLongLittleEndian(File,SamplingRate))
  229.             {
  230.                 goto DiskErrorPoint;
  231.             }
  232.  
  233.         /*  4-byte little endian average bytes per second. */
  234.         if (!WriteBufferedUnsignedLongLittleEndian(File,BytesPerSecond))
  235.             {
  236.                 goto DiskErrorPoint;
  237.             }
  238.  
  239.         /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  240.         /*    stereo, this is 4. */
  241.         if (!WriteBufferedUnsignedShortLittleEndian(File,BlockAlignment))
  242.             {
  243.                 goto DiskErrorPoint;
  244.             }
  245.  
  246.         /*  2-byte little endian number of bits. */
  247.         /*      - 8 = 8-bit */
  248.         /*      - 16 = 16-bit */
  249.         switch (GetSampleStorageActualNumBits(Sample))
  250.             {
  251.                 default:
  252.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  253.                         "GetSampleStorageActualNumBits"));
  254.                     break;
  255.                 case eSample8bit:
  256.                     if (!WriteBufferedUnsignedShortLittleEndian(File,8))
  257.                         {
  258.                             goto DiskErrorPoint;
  259.                         }
  260.                     break;
  261.                 case eSample16bit:
  262.                     if (!WriteBufferedUnsignedShortLittleEndian(File,16))
  263.                         {
  264.                             goto DiskErrorPoint;
  265.                         }
  266.                     break;
  267.             }
  268.  
  269.         /*  'data' */
  270.         if (!WriteBufferedOutput(File,4,"data"))
  271.             {
  272.                 goto DiskErrorPoint;
  273.             }
  274.  
  275.         /*  4-byte little endian length of sample data descriptor */
  276.         if (!WriteBufferedUnsignedLongLittleEndian(File,TotalSampleLength))
  277.             {
  278.                 goto DiskErrorPoint;
  279.             }
  280.  
  281.         /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  282.         /*    from -32768 to 32767. */
  283.         switch (GetSampleStorageActualNumBits(Sample))
  284.             {
  285.                 default:
  286.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  287.                         "GetSampleStorageActualNumBits"));
  288.                     break;
  289.                 case eSample8bit:
  290.                     switch (GetSampleStorageActualNumChannels(Sample))
  291.                         {
  292.                             default:
  293.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  294.                                     "GetSampleStorageActualNumBits"));
  295.                                 break;
  296.                             case eSampleMono:
  297.                                 {
  298.                                     long                        Limit;
  299.                                     long                        Scan;
  300.  
  301.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  302.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  303.                                         {
  304.                                             largefixedsigned        SampleWord;
  305.  
  306.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  307.                                             if (!WriteBufferedUnsignedChar(File,
  308.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  309.                                                 {
  310.                                                     goto DiskErrorPoint;
  311.                                                 }
  312.                                         }
  313.                                 }
  314.                                 break;
  315.                             case eSampleStereo:
  316.                                 {
  317.                                     long                        Limit;
  318.                                     long                        Scan;
  319.  
  320.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  321.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  322.                                         {
  323.                                             largefixedsigned        SampleWord;
  324.  
  325.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  326.                                             if (!WriteBufferedUnsignedChar(File,
  327.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  328.                                                 {
  329.                                                     goto DiskErrorPoint;
  330.                                                 }
  331.  
  332.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  333.                                             if (!WriteBufferedUnsignedChar(File,
  334.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  335.                                                 {
  336.                                                     goto DiskErrorPoint;
  337.                                                 }
  338.                                         }
  339.                                 }
  340.                                 break;
  341.                         }
  342.                     break;
  343.                 case eSample16bit:
  344.                     switch (GetSampleStorageActualNumChannels(Sample))
  345.                         {
  346.                             default:
  347.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  348.                                     "GetSampleStorageActualNumBits"));
  349.                                 break;
  350.                             case eSampleMono:
  351.                                 {
  352.                                     long                        Limit;
  353.                                     long                        Scan;
  354.  
  355.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  356.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  357.                                         {
  358.                                             largefixedsigned        SampleWord;
  359.  
  360.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  361.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  362.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  363.                                                 {
  364.                                                     goto DiskErrorPoint;
  365.                                                 }
  366.                                         }
  367.                                 }
  368.                                 break;
  369.                             case eSampleStereo:
  370.                                 {
  371.                                     long                        Limit;
  372.                                     long                        Scan;
  373.  
  374.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  375.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  376.                                         {
  377.                                             largefixedsigned        SampleWord;
  378.  
  379.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  380.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  381.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  382.                                                 {
  383.                                                     goto DiskErrorPoint;
  384.                                                 }
  385.  
  386.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  387.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  388.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  389.                                                 {
  390.                                                     goto DiskErrorPoint;
  391.                                                 }
  392.                                         }
  393.                                 }
  394.                                 break;
  395.                         }
  396.                     break;
  397.             }
  398.  
  399.         return True;
  400.     }
  401.